#include <iostream> // cout
#include <cmath> // sin cos
#include <GL/glut.h>
#include <vector>
#include <time.h>

using namespace std;

double cep=0.85; //coeficiente de elasticidad esferas vs paredes
double cee=0.85; //coeficiente de elasticidad esferas vs esferas
double a=-.09;


//******************************************************************//
//    CLASE ESFERA manejará todo lo referido a cada una de          //
//	    las esferas que aparezcan en la representación              //
//******************************************************************//

class esfera{
 
private:
  double centro[3]; //centro de la esfera (en la pos 1 no pusimos nada, ya que y es constante)
  double radio; //radio de la esfera
 public:

  double vel[3]; //velocidad de cada movimiento
  double t; //mide el tiempo
  double pos[3]; //posicion de cada movimiento
  GLfloat bcolor[4];
  
    //constructor por parametros
    esfera(double inicio[], double velocidad[],GLfloat color[], double r=0.03){
    centro[0]=inicio[0]; centro[1]=inicio[1]; centro[2]=inicio[2];
	  pos[0]=inicio[0]; pos[1]=inicio[1]; pos[2]=inicio[2];
	  vel[0]=velocidad[0]; vel[1]=velocidad[1]; vel[2]=velocidad[2];
    t=0;
    radio=r;
    bcolor[0]=color[0];
    bcolor[1]=color[1];
    bcolor[2]=color[2];
    bcolor[3]=color[3];
  }

 //constructor por defecto
  esfera(){
    centro[0]=0; centro[1]=0; centro[2]=0;
	  pos[0]=0; pos[1]=0; pos[2]=0;
	  vel[0]=0; vel[1]=0; vel[2]=0;
    bcolor[0]=1;bcolor[1]=1;bcolor[2]=1;bcolor[3]=1;
    radio=0.03;
	  t=0;
  }

  //constructor por copia
  esfera& operator=(const esfera &e){
	  vel[0]=e.vel[0]; vel[1]=e.vel[1]; vel[2]=e.vel[2];
		centro[0]=e[0]; centro[1]=e[1]; centro[2]=e[2];
		pos[0]=e.pos[0]; pos[1]=e.pos[1]; pos[2]=e.pos[2];
    bcolor[0]=e.bcolor[0];bcolor[1]=e.bcolor[1];bcolor[2]=e.bcolor[2];bcolor[3]=e.bcolor[3];
		t=0; radio=0.03;
		return *this;
  }
  
  double& operator[](int i) {return centro[i];}
  
  const double& operator[](int i) const {return centro[i];}

  double get_radio(){return radio;}

  double mod_vel(){return sqrt(vel[0]*vel[0]+vel[2]*vel[2]);} // en y no hay movimiento

//intersecciones con los limites del dibujo
//verifico si no intersecta con algun limite del dibujo 
//(en x de -.5 a .5, en z de -1 a 1)
//aproximamos por 0.001
//si intersecta planteamos un nuevo tiro oblicuo
  
//pared izquierda x=-.5

  bool int_left(){  //intersección con la pared izquierda
	if ( ((centro[0]-radio)+.5) <0.001 ) 
	{
		//nuevo punto de partida, nuevas velocidades iniciales
		vel[0]=-vel[0]*cep; // en x cambia el sentido
		vel[2]=vel[2]*cep; //en z no cambia el sentido
		pos[0]=-0.467+radio;
		pos[2]=centro[2];
		centro[0]=pos[0];
		t=0;
		return true;
	}
	else
		return false;
  }


  //pared derecha x=.5

  bool int_right(){ //intersección con la pared derecha
	if ( ((centro[0]+radio)-.5) > -0.001 ) 
	{
		//nuevo punto de partida, nuevas velocidades iniciales
		vel[0]=-vel[0]*cep; // en x cambia la direccion elásticamente
		vel[2]=vel[2]*cep; //para 'z' la nueva velocidad
		pos[0]=0.467-radio;
		pos[2]=centro[2];
		centro[0]=pos[0];
		t=0;
		return true;
	}
	else
		return false;
  }

  //pared  z=-1

    bool int_near(){  //intersección con la pared frontal
	if ( ((centro[2]-radio)+1) <0.001 ) 
	{
		//nuevo punto de partida, nuevas velocidades iniciales
		vel[2]=-vel[2]*cep; // en z cambia el sentido
		vel[0]=vel[0]*cep; //para 'x' no cambia el sentido
		pos[2]=-0.967+radio;
		pos[0]=centro[0];
		centro[2]=pos[2];
		t=0;
		return true;
	}
	else
		return false;
  }


  //pared z=1

  bool int_far(){ //intersección con la pared trasera
	if ( ((centro[2]+radio)-1) > -0.01 ) 
	{
		//nuevo punto de partida, nuevas velocidades iniciales
		vel[2]=-vel[2]*cep; // en z cambia la direccion elásticamente
		vel[0]=vel[0]*cep; //para 'x' la nueva velocidad
		pos[2]=0.967-radio;
		pos[0]=centro[0];
		centro[2]=pos[2];
		t=0;
		return true;
	}
	else
		return false;
  }
 
  void nueva_posicion(){  //calcula la nueva posición de la esfera
	//calculo el tiempo
	t=t+0.015;
	
	centro[0]=pos[0]+vel[0]*t + .5*(a)*(t*t);
	centro[2]=pos[2]+vel[2]*t + .5*(a)*(t*t);

	double mod_vel=0;
	
        //llama a los cálculos de intersecciones
	this->int_left();
	this->int_right();
	this->int_near();
	this->int_far();
	

  }

  //Intersección entre esferas
  //para la interseccion entre las esferas hay que tener en cuenta que poseen IGUAL MASA

  bool interseccion_esferas(esfera &esf){
	double dif_x = centro[0]-esf[0];
	double dif_z = centro[2]-esf[2];
	double mod_dif = sqrt(dif_x*dif_x+dif_z*dif_z);
		
         //si estan sus centros a una distancia menor 
	//a la suma de sus radios entonces se intersectan
	
	if(mod_dif<(radio+esf.get_radio()))
	{
		cout<<"interseccion de esferas"<<endl;
		//vectores velocidad en el momento de la interseccion
		double v1[]= {vel[0],vel[2]}; //velocidad de esfera 1
		double v2[]= {esf.vel[0],esf.vel[2]}; //velocidad de esfera 2
		double a[] = {dif_x,dif_z}; //Vector del centro de una circunferencia al centro de la otra 
		double mod2_a = a[0]*a[0]+a[2]*a[2]; //El cuadrado del modulo
		
		if(mod2_a==0) return false; //nunca será cero, pero por las dudas
		
		//nuevos movimientos para ambas esferas
		//vuelvo el tiempo a cero y la posicion inicial a la actual
		//desplazo un poquito en direccion opuesta para perder la intersección
		esf.t=0;
		t=0;
		pos[0]=centro[0]+a[0]*0.0005;
		pos[2]=centro[2]+a[0]*0.0005;
		esf.pos[0]=esf.centro[0]-a[0]*0.0005;
		esf.pos[2]=esf.centro[2]-a[2]*0.0005;

		
		//primero verifico si alguna esta quieta
		//choque perfectamente elastico, la velocidad q traía una pasa a la otra
		//multiplicada por un coeficiente elastico entre ambas esferas
		double mod2_v1 = v1[0]*v1[0]+v1[2]*v1[2]; //El cuadrado del modulo
		double mod2_v2 = v2[0]*v2[0]+v2[2]*v2[2]; //El cuadrado del modulo

		if(mod2_v1<0.001)
		{
			vel[0]=cee*v2[0];
			vel[1]=cee*v2[1];
			vel[2]=cee*v2[2];
			esf.vel[0]=0;
			esf.vel[2]=0;
			return true;
		}
		if(mod2_v2<0.001)
		{
			esf.vel[0]=cee*v1[0];
			esf.vel[2]=cee*v2[2];
			vel[0]=0;
			vel[2]=0;
			return true;
		}
		
		
		//Para el calculo de las nuevas velocidades se calculará acorde a las imagenes adjuntadas (int_esf1.jpg e int_esf2.jpg)
		//solo que se las ha generalizado a 3 dimensiones
		
		//proyecto v1 y v2 sobre a y obtengo v1p y v2p 
		//proy a V = ((a.V)/|a|^2).a  (los puntos indican producto punto y las barras modulo)
		
		double pp_v1 = a[0]*v1[0]+a[2]*v1[2]; //producto punto con v1
		double pp_v2 = a[0]*v2[0]+a[2]*v2[2]; //producto punto con v2
		
		pp_v1/=mod2_a; // Calculo de (a.v1)/|a|^2
		pp_v2/=mod2_a; // Calculo de (a.v2)/|a|^2

		double v1p[]={pp_v1*a[0],pp_v1*a[2]};
		double v2p[]={pp_v2*a[0],pp_v2*a[2]};

		//para calcular v1c y v2c simplemente hago la resta de vectores
		double v1c[]={v1[0]-v1p[0],v1[2]-v1p[2]};
		double v2c[]={v2[0]-v2p[0],v2[2]-v2p[2]};

		//con los nuevos datos puedo calcular los nuevos vectores velocidad
		vel[0]=v1c[0]+v2p[0];
		vel[2]=v1c[2]+v2p[2];

		esf.vel[0]=v2c[0]+v1p[0];
	  	esf.vel[2]=v2c[2]+v1p[2];
        
		return true;
	}

	return false;
  
  }
   
}; //FIN clase esfera


